#include "../utils.hpp"

float vertices[] = {
    // positions          // normals           // texture coords
    -0.5f, -0.5f, -0.5f, 0.0f,  0.0f,  -1.0f, 0.0f, 0.0f, 0.5f,  -0.5f, -0.5f, 0.0f,  0.0f,  -1.0f, 1.0f, 0.0f,
    0.5f,  0.5f,  -0.5f, 0.0f,  0.0f,  -1.0f, 1.0f, 1.0f, 0.5f,  0.5f,  -0.5f, 0.0f,  0.0f,  -1.0f, 1.0f, 1.0f,
    -0.5f, 0.5f,  -0.5f, 0.0f,  0.0f,  -1.0f, 0.0f, 1.0f, -0.5f, -0.5f, -0.5f, 0.0f,  0.0f,  -1.0f, 0.0f, 0.0f,

    -0.5f, -0.5f, 0.5f,  0.0f,  0.0f,  1.0f,  0.0f, 0.0f, 0.5f,  -0.5f, 0.5f,  0.0f,  0.0f,  1.0f,  1.0f, 0.0f,
    0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f, 1.0f, 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f, 1.0f,
    -0.5f, 0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f, 1.0f, -0.5f, -0.5f, 0.5f,  0.0f,  0.0f,  1.0f,  0.0f, 0.0f,

    -0.5f, 0.5f,  0.5f,  -1.0f, 0.0f,  0.0f,  1.0f, 0.0f, -0.5f, 0.5f,  -0.5f, -1.0f, 0.0f,  0.0f,  1.0f, 1.0f,
    -0.5f, -0.5f, -0.5f, -1.0f, 0.0f,  0.0f,  0.0f, 1.0f, -0.5f, -0.5f, -0.5f, -1.0f, 0.0f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, 0.5f,  -1.0f, 0.0f,  0.0f,  0.0f, 0.0f, -0.5f, 0.5f,  0.5f,  -1.0f, 0.0f,  0.0f,  1.0f, 0.0f,

    0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f, 0.5f,  0.5f,  -0.5f, 1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
    0.5f,  -0.5f, -0.5f, 1.0f,  0.0f,  0.0f,  0.0f, 1.0f, 0.5f,  -0.5f, -0.5f, 1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    0.5f,  -0.5f, 0.5f,  1.0f,  0.0f,  0.0f,  0.0f, 0.0f, 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

    -0.5f, -0.5f, -0.5f, 0.0f,  -1.0f, 0.0f,  0.0f, 1.0f, 0.5f,  -0.5f, -0.5f, 0.0f,  -1.0f, 0.0f,  1.0f, 1.0f,
    0.5f,  -0.5f, 0.5f,  0.0f,  -1.0f, 0.0f,  1.0f, 0.0f, 0.5f,  -0.5f, 0.5f,  0.0f,  -1.0f, 0.0f,  1.0f, 0.0f,
    -0.5f, -0.5f, 0.5f,  0.0f,  -1.0f, 0.0f,  0.0f, 0.0f, -0.5f, -0.5f, -0.5f, 0.0f,  -1.0f, 0.0f,  0.0f, 1.0f,

    -0.5f, 0.5f,  -0.5f, 0.0f,  1.0f,  0.0f,  0.0f, 1.0f, 0.5f,  0.5f,  -0.5f, 0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
    0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f, 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
    -0.5f, 0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f, 0.0f, -0.5f, 0.5f,  -0.5f, 0.0f,  1.0f,  0.0f,  0.0f, 1.0f};

// 平面位置，处于左下角
float quadVertices[] = {
    // positions	// textures
    -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
    -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,  -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,  1.0f, 1.0f};

// 当前路径
#define SOURCE_PATH ROOT_SOURCE_PATH "/src/core/frame/"

int width = 800, height = 600;
std::shared_ptr<Shader> instanceShader, frameShader;
unsigned int basicVAO, basicVBO, frameVAO, frameVBO, frameID, skyboxTex;

void init()
{
    instanceShader = std::make_shared<Shader>(SOURCE_PATH "test.vert", SOURCE_PATH "test.frag", nullptr);
    frameShader = std::make_shared<Shader>(SOURCE_PATH "frame.vert", SOURCE_PATH "frame.frag", nullptr);

    // 启用深度测试
    glEnable(GL_DEPTH_TEST);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    // basic shader
    {
        glGenVertexArrays(1, &basicVAO);
        glGenBuffers(1, &basicVBO);

        glBindVertexArray(basicVAO);
        glBindBuffer(GL_ARRAY_BUFFER, basicVBO);

        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
        glEnableVertexAttribArray(0);

        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(3 * sizeof(float)));
        glEnableVertexAttribArray(1);

        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(6 * sizeof(float)));
        glEnableVertexAttribArray(2);
    }

    // frame shader
    {
        glGenVertexArrays(1, &frameVAO);
        glGenBuffers(1, &frameVBO);

        glBindVertexArray(frameVAO);
        glBindBuffer(GL_ARRAY_BUFFER, frameVBO);

        glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);

        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
        glEnableVertexAttribArray(0);

        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));
        glEnableVertexAttribArray(1);
    }

    // 创建帧缓冲、和要附加的纹理以及渲染缓冲对象
    unsigned int RBO;
    glGenFramebuffers(1, &frameID);
    glGenTextures(1, &skyboxTex);
    glGenRenderbuffers(1, &RBO);

    // 绑定到当前帧缓冲
    glBindFramebuffer(GL_FRAMEBUFFER, frameID);

    // 创建纹理附件
    glBindTexture(GL_TEXTURE_2D, skyboxTex);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    // 创建渲染缓冲对象
    glBindRenderbuffer(GL_RENDERBUFFER, RBO);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
    glBindRenderbuffer(GL_RENDERBUFFER, 0);

    // 将纹理和渲染缓冲对象附加到帧缓冲
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, skyboxTex, 0);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO);

    // 检查帧缓冲是否完整
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cerr << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;

    // 解绑帧缓冲，恢复默认状态
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // 载入光照信息
    instanceShader->enable();
    instanceShader->set_value("projection", camera->projection());

    instanceShader->set_value("lightPos", Vec3f(10.0f, 10.0f, 10.0f));
    instanceShader->set_value("lightColor", Vec3f(1.0f, 1.0f, 1.0f));
    instanceShader->set_value("objectColor", Vec3f(1.0f, 0.5f, 0.31f));
}

void render()
{
    // 刷新视图矩阵
    instanceShader->enable();
    instanceShader->set_value("model", Mat4x4<float>::identity());
    instanceShader->set_value("fix", Mat4x4<float>::identity());
    instanceShader->set_value("view", camera->view());
    instanceShader->set_value("viewPos", camera->position());

    // 绑定帧缓冲，绘制立方体
    glBindFramebuffer(GL_FRAMEBUFFER, frameID);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindVertexArray(basicVAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);

    // 绘制完成解除绑定
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // 开始将绘制好的 frame 中的纹理绘制到屏幕
    frameShader->enable();
    frameShader->set_value("tex", 0);
    frameShader->set_value("alpha", 1.0f);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glBindVertexArray(frameVAO);
    glBindTexture(GL_TEXTURE_2D, skyboxTex);

    glDrawArrays(GL_TRIANGLES, 0, 6);
}

int main()
{
    GLFWwindow *window = initProgram();
    if (window == nullptr)
        return -1;

    // 创建顶点数据
    init();

    // 开启消息循环
    while (!glfwWindowShouldClose(window))
    {
        // 渲染指令
        render();

        // 交换缓冲，处理并调用事件
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 销毁资源
    glfwTerminate();

    return 0;
}